#include "hj212_client_port.h"

#define HJ_LOG_TAG  "hj212.sourceport"        // 日志标签
#define HJ_LOG_LVL HJ_DBG_INFO          // 日志等级
#include "hjdebug.h"

/**********************************************************************************
 * 更新实时数据
 *********************************************************************************/
static void hj212port_updata_rtdata_msg(storage_save_t *record, struct hj212_datamsg *msg, int serverno)
{
    const server_param_t *config = &sys_param->server_param[serverno];
    storage_real_val_t *pollist = record->data.real.val;
    msg->datatime = record->time;
    for (int i = 0; i < STORAGE_SAVE_MAX; i++)
    {
        if (pollist[i].pol_index && !pollist[i].pol_group && pollist[i].pol_index < CODE_TABLE_ID_MAP_ZHESUAN)
        {
            struct pol_rtval rtval;
            memset(&rtval, 0, sizeof(rtval));
            rtval.param.codeid = pollist[i].pol_index;
            rtval.value = pollist[i].cur_val;

            // 折算值
            for (int tmp = 0; tmp < STORAGE_SAVE_MAX; tmp++)
            {
                if ((pollist[i].pol_index + CODE_TABLE_ID_MAP_ZHESUAN) == pollist[tmp].pol_index)
                {
                    rtval.enable_flag |= HJ212_ZSRTD_ENABLE;
                    rtval.zs_value = pollist[tmp].cur_val;
                    break;
                }
            }

            /* 查找污染物参数 */
            pol_code_table_t pol_code;
            memset(&pol_code, 0, sizeof(pol_code));
            code_table_get_pol_item_by_id(rtval.param.codeid, &pol_code);
            const pol_param_t *pol_config = find_pol_from_group(0, rtval.param.codeid, NULL, NULL);
            rtval.param.decimal_num = pol_config ? pol_config->dec_point : 4;


            strncpy(rtval.param.code,
                    config->comm_prot == HJ212_2005_COMM_PROT_ENUM ?
                    pol_code.old_code : pol_code.new_code, HJ212_POLCODE_MAX_LEN);

            if (strlen(rtval.param.code) <= 0)
            {
                snprintf(rtval.param.code, HJ212_POLCODE_MAX_LEN, "CODEID-%d", rtval.param.codeid);
            }

            memcpy(&rtval.datamark, &pollist[i].flag, sizeof(pollist[i].flag));
            gen_blk_queue_push_block(&msg->queue, (void *)&rtval);
        }
    }
}
/**********************************************************************************
 * 更新历史数据
 *********************************************************************************/
static void hj212port_updata_hisdata_msg(storage_save_t *record, struct hj212_datamsg *msg, int serverno)
{
    const server_param_t *config = &sys_param->server_param[serverno];
    storage_his_val_t *pollist = record->data.his.val;
    msg->datatime = record->time;
    for (int i = 0; i < STORAGE_SAVE_MAX; i++)
    {
        if (pollist[i].pol_index && !pollist[i].pol_group && pollist[i].pol_index < CODE_TABLE_ID_MAP_ZHESUAN)
        {
            struct pol_his_data hisval;
            memset(&hisval, 0, sizeof(hisval));

            hisval.param.codeid = pollist[i].pol_index;
            hisval.min = pollist[i].min;
            hisval.avg = pollist[i].avg;
            hisval.max = pollist[i].max;
            hisval.cou = pollist[i].cou;
            hisval.total = pollist[i].total;

            // 折算值
            for (int tmp = 0; tmp < STORAGE_SAVE_MAX; tmp++)
            {
                if ((pollist[i].pol_index + CODE_TABLE_ID_MAP_ZHESUAN) == pollist[tmp].pol_index)
                {
                    hisval.enable_flag |= HJ212_ZSHIS_ENABLE;
                    hisval.zs_avg = pollist[tmp].avg;
                    hisval.zs_max = pollist[tmp].max;
                    hisval.zs_min = pollist[tmp].min;
                    break;
                }
            }

            /* 查找污染物参数 */
            pol_code_table_t pol_code;
            memset(&pol_code, 0, sizeof(pol_code));
            code_table_get_pol_item_by_id(hisval.param.codeid, &pol_code);
            const pol_param_t *pol_config = find_pol_from_group(0, hisval.param.codeid, NULL, NULL);
            hisval.param.decimal_num = pol_config ? pol_config->dec_point : 4;

            strncpy(hisval.param.code,
                    config->comm_prot == HJ212_2005_COMM_PROT_ENUM ?
                    pol_code.old_code : pol_code.new_code, HJ212_POLCODE_MAX_LEN);

            if (strlen(hisval.param.code) <= 0)
            {
                snprintf(hisval.param.code, HJ212_POLCODE_MAX_LEN, "CODEID-%d", hisval.param.codeid);
            }

            memcpy(&hisval.datamark, &pollist[i].flag, sizeof(pollist[i].flag));
            hisval.enable_flag |= HJ212_COU_ENABLE | HJ212_HISFLAG_ENABLE;
            gen_blk_queue_push_block(&msg->queue, (void *)&hisval);
        }
    }
}
/**********************************************************************************
 * 长期支持数据源的isempty
 *********************************************************************************/
static struct hj212_datamsg *hj212port_longtime_push_source_references(struct hj212_datasource *source)
{
    struct port_longtime_push_source *this = (struct port_longtime_push_source *)source;

    gen_blk_queue_reset(&this->msg.queue);

    return &this->msg;
}

/**********************************************************************************
 * 长期支持数据源的isempty
 *********************************************************************************/
static int hj212port_longtime_push_source_is_empty(struct hj212_datasource *source)
{
    struct port_longtime_push_source *this = (struct port_longtime_push_source *)source;
    struct port_hj212_client *client = this->client;
    struct hj212_runinfo_block *info = hj212_runinfo_block_get_instance(client->parent.id);

    if (!info)      // 没有info直接认为空
    {
        HJ_LOG_E("#%d longtime_push_source no runinfo_block", client->parent.id);
        return !0;
    }

    return storage_get_wptr_pos(this->type) == info->rptr[this->type];
}

/**********************************************************************************
 * 长期支持数据源的next
 *********************************************************************************/
static int hj212port_longtime_push_source_next(struct hj212_datasource *source, struct hj212_datamsg *msg)
{
    struct port_longtime_push_source *this = (struct port_longtime_push_source *)source;
    struct port_hj212_client *client = this->client;
    struct hj212_runinfo_block *info = hj212_runinfo_block_get_instance(client->parent.id);

    if (!info)      // 没有info直接认为空
    {
        HJ_LOG_E("#%d longtime_push_source no runinfo_block", client->parent.id);
        return -1;
    }

    int rptr = info->rptr[this->type];
    if (storage_get_wptr_pos(this->type) == rptr)
    {
        return -1;
    }
    if (storage_get_record(this->type, rptr, &this->record) == STORE_ERR_NONE)
    {
        if (this->type == HJ212_MSG_TYPE_RTD)
        {
            hj212port_updata_rtdata_msg(&this->record, msg, client->parent.id);
        }
        else
        {
            hj212port_updata_hisdata_msg(&this->record, msg, client->parent.id);
        }
    }
    /* 这部分处理待优化 */
    if (++rptr >= storage_get_record_max(this->type))
    {
        rptr = 0;
    }
    info->rptr[this->type] = rptr;
    hj212_runinfo_block_save(client->parent.id);
    return 0;
}

/**********************************************************************************
 * 时间段数据源的references
 *********************************************************************************/
static struct hj212_datamsg *hj212port_time_section_source_references(struct hj212_datasource *source)
{
    struct port_time_section_source *this = (struct port_time_section_source *)source;

    gen_blk_queue_reset(&this->msg.queue);

    return &this->msg;
}

/**********************************************************************************
 * 时间段数据源的isempty
 *********************************************************************************/
static int hj212port_time_section_source_is_empty(struct hj212_datasource *source)
{
    struct port_time_section_source *this = (struct port_time_section_source *)source;
    return this->begin == this->end;
}

/**********************************************************************************
 * 时间段数据源的next
 *********************************************************************************/
static int hj212port_time_section_source_next(struct hj212_datasource *source, struct hj212_datamsg *msg)
{
    struct port_time_section_source *this = (struct port_time_section_source *)source;
    struct port_hj212_client *client = (struct port_hj212_client *)this->client;
    if (this->begin == this->end)
    {
        return -1;
    }
    if (storage_get_record(this->type, this->begin, &this->record) == STORE_ERR_NONE)
    {
        if (this->type == HJ212_MSG_TYPE_RTD)
        {
            hj212port_updata_rtdata_msg(&this->record, msg, client->parent.id);
        }
        else
        {
            hj212port_updata_hisdata_msg(&this->record, msg, client->parent.id);
        }
    }
    /* 这部分处理待优化 */
    if (++this->begin >= storage_get_record_max(this->type))
    {
        this->begin = 0;
    }
    return 0;
}
/* 外部推送状态参数数据到数据源 */
void hj212_pol_state_pushsource(struct pol_state_source *source,
                                int polcodeid,
                                int statecodeid,
                                variant_type *value,
                                time_t time)
{
    struct pol_state_item *state;
    rt_list_for_each_entry(state, &source->usedlist, list)
    {
        if (state->polcodeid == polcodeid && state->statecodeid == statecodeid)
        {
            goto __exit;
        }
    }
    /* 以前不存在则创建一个新的 */
    if (rt_list_isempty(&source->freelist)) // 状态参数列表不够
    {
        /* 再申请一个节点 */
        state = hj212port_calloc(1, sizeof(*state));
        if (!state)
            goto __err;
        rt_list_init(&state->list);
    }
    else
    {
        state = rt_list_entry(source->freelist.next, struct pol_state_item, list);
        rt_list_remove(&state->list);
    }

    state->polcodeid = polcodeid;
    state->statecodeid = statecodeid;
    rt_list_insert_before(&source->usedlist, &state->list);
__exit:
    state->time = time;
    VT_COPY(&state->value, value);
    osTimerStart(source->timer, 200);   // 等待200Tick
__err:
    return;
}
static struct hj212_datamsg *polstate_source_references(struct hj212_datasource *source)
{
    struct pol_state_source *this = (struct pol_state_source *)source;

    gen_blk_queue_reset(&this->msg.parent.queue);

    return &this->msg.parent;
}

static int polstate_source_is_empty(struct hj212_datasource *source)
{
    struct pol_state_source *this = (struct pol_state_source *)source;

    if (rt_list_isempty(&this->usedlist))
    {
        return 1;   // 数据源为空，返回True
    }

    if (osTimerIsRunning(this->timer))
    {
        return 1;   // 数据源为空，返回True
    }

    return 0;
}

static struct pol_state *pol_state_item_to_pol_state(struct pol_state *dst, struct pol_state_item *src)
{
    code_table_get_sp_code_name_by_id(src->statecodeid, dst->param.code, sizeof(dst->param.code));
    VT_TOSTRING(src->value, dst->value, sizeof(dst->value));
    dst->param.codeid = src->statecodeid;
    dst->param.decimal_num = src->value.accuracy;

    if (strlen(dst->param.code) <= 0)
    {
        snprintf(dst->param.code, HJ212_POLCODE_MAX_LEN, "STATE-%d", dst->param.codeid);
    }
    return dst;
}

static int polstate_source_next(struct hj212_datasource *source, struct hj212_datamsg *msg)
{
    struct pol_state_source *this = (struct pol_state_source *)source;

    if (rt_list_isempty(&this->usedlist))
        return 1;   // 数据源为空，返回True

    /* 拿到需要填充的msg */
    struct hj212_polstate_msg *statemsg = (struct hj212_polstate_msg *)msg;
    /* 取出第一条, 拿到polcode */
    struct pol_state_item *polstate_head = rt_list_first_entry(&this->usedlist, struct pol_state_item, list);
    rt_list_remove(&polstate_head->list);

    /* 获取污染物参数 - 主要为了 statemsg->polcode 和 datatime 字段 */
    pol_code_table_t pol_code;
    memset(&pol_code, 0, sizeof(pol_code));
    if (code_table_get_pol_item_by_id(polstate_head->polcodeid, &pol_code) == OK_RES_ENUM)
    {
        const server_param_t *config = &sys_param->server_param[this->client->parent.id];

        strncpy(statemsg->polcode,
                config->comm_prot == HJ212_2005_COMM_PROT_ENUM ?
                pol_code.old_code : pol_code.new_code, HJ212_POLCODE_MAX_LEN);
    }
    statemsg->parent.datatime = polstate_head->time;
    if (strlen(statemsg->polcode) <= 0)
        snprintf(statemsg->polcode, HJ212_POLCODE_MAX_LEN, "CODEID-%d", polstate_head->polcodeid);
    /* 推送到msg的队列 */
    struct pol_state queueitem;
    gen_blk_queue_push_block(&statemsg->parent.queue,
                             (void *)pol_state_item_to_pol_state(&queueitem, polstate_head));

    struct pol_state_item *pos, *tmp;
    rt_list_for_each_entry_safe(pos, tmp, &this->usedlist, list)
    {
        if (pos->polcodeid == polstate_head->polcodeid)
        {
            rt_list_remove(&pos->list); // pos脱离链表
            gen_blk_queue_push_block(&statemsg->parent.queue,
                                     (void *)pol_state_item_to_pol_state(&queueitem, pos));
            // 回收pos
            rt_list_insert_before(&this->freelist, &pos->list);
        }
    }
    /* 回收polstate_head到freelist */
    rt_list_insert_before(&this->freelist, &polstate_head->list);
    return 0;
}

static void polstate_source_timeout_handle(void *argument)
{
    // 没啥好做的
}

int static_datasource_init(struct port_hj212_client *client)
{
    for (int i = 0; i <= HJ212_MSG_TYPE_DAY; i++)   // 实时数据 / 分钟数据 / 小时数据 / 日数据
    {
        struct port_longtime_push_source *source = &client->datasource[i];

        int typesize = hj212_datamsg_typesize(i);
        HJ_ASSERT(typesize > 0);
        void *msgpool = hj212port_malloc(typesize * HJ212_POL_MAXNUM_IN_QUEUE);
        HJ_ASSERT(msgpool != NULL);
        hj212_datamsg_init(&source->msg, i, msgpool, typesize * HJ212_POL_MAXNUM_IN_QUEUE);

        source->client = client;
        source->type = i;
        source->parent.is_empty = hj212port_longtime_push_source_is_empty;
        source->parent.next = hj212port_longtime_push_source_next;
        source->parent.references = hj212port_longtime_push_source_references;
        source->parent.dereference = NULL;
    }

    struct pol_state_source *state_source = &client->polstate_datasource;

    int typesize = hj212_datamsg_typesize(HJ212_MSG_TYPE_POLSTETE);
    HJ_ASSERT(typesize > 0);
    void *msgpool = hj212port_malloc(typesize * HJ212_POLSTATE_MAXNUM_IN_QUEUE);
    HJ_ASSERT(msgpool != NULL);
    hj212_datamsg_init(&state_source->msg.parent,
                       HJ212_MSG_TYPE_POLSTETE,
                       msgpool,
                       typesize * HJ212_POLSTATE_MAXNUM_IN_QUEUE);
    rt_list_init(&state_source->freelist);
    rt_list_init(&state_source->usedlist);
    state_source->timer = osTimerNew(polstate_source_timeout_handle, osTimerOnce, NULL, NULL);
    HJ_ASSERT(state_source->timer);
    state_source->parent.is_empty = polstate_source_is_empty;
    state_source->parent.next = polstate_source_next;
    state_source->parent.references = polstate_source_references;
    state_source->parent.dereference = NULL;
    state_source->client = client;

    return 0;
}


/**********************************************************************************
 * 铁电相关 - 存储发送指针
 *********************************************************************************/
static struct hj212_runinfo_block run_info[8] = {0};

void hj212_runinfo_block_save(int no)
{
    struct hj212_runinfo_block *info = &run_info[no];
    info->crc = 0;
    uint16_t crc = HJ212_CRC16((void *)info, sizeof(*info));
    info->crc = crc;
    fm25cl6_write_nbyte((void *)info, RUNINFO_ADDR_BEGIN + sizeof(*info) * no, sizeof(*info));
}

static void hj212_runinfo_block_reset(struct hj212_runinfo_block *info)
{
    memset(info, 0, sizeof(*info));
    for (int i = 0; i <= STORAGE_TYPE_YEAR; i++)
    {
        int wptr = storage_get_wptr_pos(i);
        info->rptr[i] = wptr;
    }
    info->magic = RUNINFO_MAGIC;
}

static void hj212_runinfo_block_init(int no)
{
    if (no >= 0 && no < RUNINFO_BLOCK_NUM)
    {
        struct hj212_runinfo_block *info = &run_info[no];

        fm25cl6_read_nbyte((void *)info, RUNINFO_ADDR_BEGIN + sizeof(*info) * no, sizeof(*info));
        if ((info->magic & RUNINFO_MARK) != RUNINFO_MAGIC) // 校验magic
        {
            hj212_runinfo_block_reset(info);
            hj212_runinfo_block_save(no);
        }
        else
        {
            uint16_t readcrc = info->crc;
            info->crc = 0;
            uint16_t crc = HJ212_CRC16((void *)info, sizeof(*info));
            if (crc != readcrc)
            {
                hj212_runinfo_block_reset(info);
                hj212_runinfo_block_save(no);
            }
        }
    }
}

struct hj212_runinfo_block *hj212_runinfo_block_get_instance(int no)
{
    if (no >= 0 && no < RUNINFO_BLOCK_NUM)
    {
        struct hj212_runinfo_block *info = &run_info[no];

        if ((info->magic & RUNINFO_MARK) != RUNINFO_MAGIC)  // 校验magic
        {
            hj212_runinfo_block_init(no);
        }
        return info;
    }
    return NULL;
}

/**********************************************************************************
 * 提供给HJ212的数据源相关Port
 *********************************************************************************/
struct hj212_datasource *hj212port_get_data_source(struct hj212_client *client, int type)
{
    struct port_hj212_client *this = (struct port_hj212_client *)client;
    if (type >= 0 && type <= HJ212_MSG_TYPE_DAY)
    {
        return &this->datasource[type].parent;
    }
    if (type == HJ212_MSG_TYPE_POLSTETE)
    {
        return &this->polstate_datasource.parent;
    }
    return NULL;
}

struct hj212_datasource *hj212port_create_hisdata_source(struct hj212_client *client, int type, time_t begin, time_t end)
{
    if (type >= 0 && type <= HJ212_MSG_TYPE_DAY)
    {
        struct port_time_section_source *source = hj212port_malloc(sizeof(struct port_time_section_source));
        if (source)
        {
            int typesize = hj212_datamsg_typesize(type);
            HJ_ASSERT(typesize > 0);
            void *msgpool = hj212port_malloc(typesize * HJ212_POL_MAXNUM_IN_QUEUE);
            if (!msgpool)
            {
                hj212port_free(source);
                return NULL;
            }
            hj212_datamsg_init(&source->msg, type, msgpool, typesize * HJ212_POL_MAXNUM_IN_QUEUE);
            source->client = (struct port_hj212_client *)client;
            source->type = type;
            source->parent.is_empty = hj212port_time_section_source_is_empty;
            source->parent.next = hj212port_time_section_source_next;
            source->parent.references = hj212port_time_section_source_references;
            source->parent.dereference = NULL;

            if (begin > end)
            {
                int tmp = end;
                end = begin;
                begin = tmp;
            }
            /* 这个部分需要优化 */
            source->begin = storage_search(type, begin);
            source->end = storage_search(type, end) + 1;

            return &source->parent;
        }
    }
    return NULL;
}

void hj212port_delete_data_source(struct hj212_client *client, struct hj212_datasource *source)
{
    struct port_time_section_source *this = (struct port_time_section_source *)source;
    hj212port_free(this->msg.queue.mempool);
    hj212port_free(source);
}







